import UIKit

/* XCode15的Swift版本5.9 */

/* Swift枚举型 */
// 定义方法
enum Month : Int{
    // 已经不要求首字母必须大写了
    case January = 1
    case February
    case March
    case April
    case May
    case June
    case July
    case August
    case September
    case October
    case November
    case December = -1
}

// 更为紧凑的定义方法
enum narrowMonth {
    case January, February, March, April, May, June, July, August, September, October, November, December
}

// 两种定义变量方法
var thisMonth = Month.August
var nextMonth : Month = .September

// 运用到switch语句中
switch nextMonth {
case .January, .February, .March, .April, .May, .June:
    print("It belongs first half year")
default:
    print("It belongs second half year")
}

// 原始值
// 原始值可以为整型，也可以为字符串型、浮点型或者字符型。
// 如果原始值取值为整型，则可以从任意一个整数开始自动递增
// 默认是从0开始递增
var rawValue = nextMonth.rawValue
let enumValue = Month(rawValue: 8)

// 如果原始值是字符串型，将自动将枚举的成员名的作为默认的原始值字符串
enum Car: String {
    case truck
    case sportsCar
    case SUV
    case MPV
    case limo
}

let myCar = Car.SUV
print("\(myCar.rawValue)")

// 关联值
enum transportFee {
    case byAir(Int, Int, Int)
    case byCar(Int, Int)
    case byTrain(Int)
}

// 有关联值时使用时必须给关联值赋值
var fromShanghaitoBeijing = transportFee.byTrain(299)
fromShanghaitoBeijing = .byAir(800, 230, 50)

// 可以通过值绑定的方式访问关联值
switch fromShanghaitoBeijing {
case .byAir(let ticketFee, let tax, let insurance) :
    print("The sum fee is \(ticketFee + tax + insurance) by air")
case .byCar(let fuelFee, let highwayFee) :
    print("The sum fee is \(fuelFee + highwayFee) by car")
case .byTrain(let ticketFee) :
    print("The sum fee is \(ticketFee) by Train")
}

// 可选型的底层实现就是一个特定的枚举型
// 该枚举型有两个枚举成员，分别为none和some
// none表示没有值的情况
// some表示可选型中含有值的情况，其关联值表示含有的具体的值
// Swift通过?、!、nil隐藏了可选型的底层实现机制

/* Swift结构体和类 */
struct Book {
    // 结构体和类的属性都可以有缺省值
    var name = ""
    var price = 0
    var category = "common"
    // Swift的结构体也可以有方法，但是没有继承等面向对象的特性
    func description() {
        print("\(name)'s price is \(price), category is \(category)")
    }
}

class Reader {
    var name = ""
    var age = 16
    var favorite: String?
    func description() {
        print("\(name) is \(age) year old, favorite is \(favorite!)")
    }
}

// 结构体是指类型，通过值复制来传递值
// 类是引用类型，通过引用值来传递值
let theReader = Reader()
print("Reader's default age is \(theReader.age)")
theReader.name = "Tommy"
theReader.age = 38
theReader.favorite = "Basketball"
theReader.description()

var anotherReader = theReader

// 引用类型要用三个等号判断引用是否是相等的
// 使用==会报错
if (anotherReader === theReader) {
    print("Equals")
}

let theBook = Book(name: "Life of Pi", price: 62, category: "adventure")
print("\(theBook.name) 's category is \(theBook.category) and price is \(theBook.price) RMB")
// Swift的结构体是值类型，赋值为常量之后不能修改其中的属性
// theBook.price = 100
theBook.description()

/* Swift类型操作符 */
class Student {
    var name : String
    var age : Int
    var id : String
    // ！！！如果没有缺省值
    // 结构体不需要一个显式的构造函数，直接在使用的时候通过函数参数的形式传入即可
    // 类需要一个显式的构造函数
    init (name: String, age : Int, id : String) {
        self.name = name
        self.age = age
        self.id = id
    }
}

// 继承
class UnderGraduate: Student {
    var classDirector : String
    init(name: String, age: Int, id : String,
         classDirector : String) {
        self.classDirector = classDirector
        super.init(name: name, age: age, id: id)
    }
}

class Graduate: Student {
    var supervisor : String
    var researchTopic : String
    init(name: String, age: Int, id: String,
         supervisor: String, researchTopic :String){
        self.supervisor = supervisor
        self.researchTopic = researchTopic
        super.init(name:name, age: age, id: id)
    }
}

// is 用来表示类型判断是否属于特定的类型
var testGraduate = Graduate(name: "Sam", age: 23, id: "SY060115", supervisor: "Tim", researchTopic: "BPM")
let students = [
    Graduate(name: "Sam", age: 23, id: "SY060115", supervisor: "Tim", researchTopic: "BPM"),
    UnderGraduate (name: "Jim", age: 19, id: "37060112", classDirector: "Lee"),
    UnderGraduate (name: "Kelly", age: 20, id: "37060113", classDirector: "Lee")];

var underGraduateNum = 0
var graduateNum = 0
for item in students {
    if item is UnderGraduate {
        underGraduateNum += 1
    } else if item is Graduate {
        graduateNum += 1
    }
}
print ("Undergraduate num is \(underGraduateNum) and graduate num is \(graduateNum)")

// as 用来表示将一个实例向下转换为它的**子类型**
// 条件转换 as? 返回一个可选值
// 强制转换 as! 强制向下转型
for item in students {
    // 当向下转型不确定是否能成功时，使用条件转换as?
    // 可以使用if进行判断避免直接强制转换引发的异常
    // 当向下转型确定可以成功时，使用强制转换as!
    // 强制转换如果失败，会触发运行时的异常
    if let theUnderGraduate = item as? UnderGraduate {
        print("\(theUnderGraduate.name)'s class director is \(theUnderGraduate.classDirector)")
    } else if let theGraduate = item as? Graduate {
        print("\(theGraduate.name)'s supervisor is \(theGraduate.supervisor)")
    }
}

/* Swift内存管理 */
// Swift使用自动引用计数（ARC）的机制来解决应用程序的内存管理
// 但是会导致强引用循环问题引发内存泄漏
// 解决强引用循环的方法是采用弱引用或无主引用
// 对于在生命周期中可能赋值为nil的实例采用弱引用，关键字为weak
// 对于在生命周期中不会赋值为nil的实例采用无主引用，关键字为unowned
